#include "tools/bash.hpp"
#include "tools/api.hpp"
#include <algorithm>
#include <cctype>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/device/file.hpp>

namespace toolsLib
{
Bash::Bash() {}

Bash::~Bash() {}

Bash& Bash::getInstance()
{
    static toolsLib::Bash instance;
    return instance;
}

bool Bash::shCmd(char* cmd)
{
    FILE* file;
    if ((file = popen(cmd, "r")) != nullptr) {
        // 读取并丢弃输出（用于执行命令但不关心输出）
        char buffer[1024];
        while (fgets(buffer, sizeof(buffer), file) != nullptr) {
            // 读取并丢弃输出
        }
        int ret = pclose(file);
        if (ret != 0) {
            LOG_ERROR("Command execution failed with return code: %d", ret);
            return false;
        }
        return true;
    } else {
        LOG_ERROR("Failed to execute command: %s", cmd);
        return false;
    }
}

bool Bash::shCmd(const std::string& cmd, std::string& result)
{
    FILE* file;
    if ((file = popen(cmd.c_str(), "r")) != nullptr) {
        char buffer[4096];
        result.clear();
        result.reserve(4096);  // 预分配空间
        
        while (fgets(buffer, sizeof(buffer), file) != nullptr) {
            result += buffer;
            // 限制最大输出大小，避免内存溢出
            if (result.size() > 1024 * 1024) {  // 1MB限制
                LOG_ERROR("Command output too large, truncated");
                break;
            }
        }
        
        int ret = pclose(file);
        if (ret != 0) {
            LOG_ERROR("Command execution failed with return code: %d", ret);
            return false;
        }
        return true;
    } else {
        LOG_ERROR("Failed to execute command: %s", cmd.c_str());
        return false;
    }
}

bool Bash::cpFile(const std::string& sourceFile, const std::string& targetFile)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path source(sourceFile);
        fs::path target(targetFile);
        
        // 如果源文件不存在，返回false
        if (!fs::exists(source)) {
            LOG_ERROR("Source file does not exist: %s", sourceFile.c_str());
            return false;
        }
        
        // 如果目标是目录，在目录中创建同名文件
        if (fs::is_directory(target)) {
            target = target / source.filename();
        } else {
            // 确保目标目录存在
            if (target.has_parent_path()) {
                fs::create_directories(target.parent_path());
            }
        }
        
        // 复制文件
        fs::copy_file(source, target, fs::copy_options::overwrite_existing);
        
        return true;
    } catch (const std::filesystem::filesystem_error& e) {
        LOG_ERROR("Failed to copy file: %s", e.what());
        return false;
    } catch (...) {
        LOG_ERROR("Unknown error occurred while copying file");
        return false;
    }
}

bool Bash::mvFile(const std::string& sourceFile, const std::string& targetFile)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path source(sourceFile);
        fs::path target(targetFile);
        
        // 如果源文件不存在，返回false
        if (!fs::exists(source)) {
            LOG_ERROR("Source file does not exist: %s", sourceFile.c_str());
            return false;
        }
        
        // 如果目标是目录，在目录中创建同名文件
        if (fs::is_directory(target)) {
            target = target / source.filename();
        } else {
            // 确保目标目录存在
            if (target.has_parent_path()) {
                fs::create_directories(target.parent_path());
            }
        }
        
        // 移动文件
        fs::rename(source, target);
        
        return true;
    } catch (const std::filesystem::filesystem_error& e) {
        LOG_ERROR("Failed to move file: %s", e.what());
        return false;
    } catch (...) {
        LOG_ERROR("Unknown error occurred while moving file");
        return false;
    }
}

bool Bash::rmFile(const std::string& file)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path filePath(file);
        
        // 如果文件不存在，返回true（类似于rm -f的行为）
        if (!fs::exists(filePath)) {
            return true;
        }
        
        // 如果是目录，返回false（应该使用rmDir）
        if (fs::is_directory(filePath)) {
            LOG_ERROR("Path is a directory, use rmDir instead: %s", file.c_str());
            return false;
        }
        
        // 删除文件
        fs::remove(filePath);
        
        return true;
    } catch (const std::filesystem::filesystem_error& e) {
        LOG_ERROR("Failed to remove file: %s", e.what());
        return false;
    } catch (...) {
        LOG_ERROR("Unknown error occurred while removing file");
        return false;
    }
}

bool Bash::mkDir(const std::string& path)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path dirPath(path);
        
        // 创建目录（包括父目录，类似于mkdir -p）
        fs::create_directories(dirPath);
        
        // 设置权限为775（rwxrwxr-x）
        fs::permissions(dirPath,
                       fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec |
                       fs::perms::group_read | fs::perms::group_write | fs::perms::group_exec |
                       fs::perms::others_read | fs::perms::others_exec,
                       fs::perm_options::replace);
        
        return true;
    } catch (const std::filesystem::filesystem_error& e) {
        LOG_ERROR("Failed to create directory: %s", e.what());
        return false;
    } catch (...) {
        LOG_ERROR("Unknown error occurred while creating directory");
        return false;
    }
}

bool Bash::rmDir(const std::string& path)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path dirPath(path);
        
        // 如果目录不存在，返回true（类似于rm -rf的行为）
        if (!fs::exists(dirPath)) {
            return true;
        }
        
        // 如果是文件，返回false（应该使用rmFile）
        if (!fs::is_directory(dirPath)) {
            LOG_ERROR("Path is not a directory, use rmFile instead: %s", path.c_str());
            return false;
        }
        
        // 递归删除目录
        fs::remove_all(dirPath);
        
        return true;
    } catch (const std::filesystem::filesystem_error& e) {
        LOG_ERROR("Failed to remove directory: %s", e.what());
        return false;
    } catch (...) {
        LOG_ERROR("Unknown error occurred while removing directory");
        return false;
    }
}

bool Bash::touch(const std::string& file)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path filePath(file);
        
        // 确保父目录存在
        if (filePath.has_parent_path()) {
            fs::create_directories(filePath.parent_path());
        }
        
        // 如果文件不存在，创建空文件
        if (!fs::exists(filePath)) {
            std::ofstream ofs(filePath);
            if (!ofs) {
                LOG_ERROR("Failed to create file: %s", file.c_str());
                return false;
            }
            ofs.close();
        } else {
            // 如果文件存在，更新修改时间
            fs::last_write_time(filePath, fs::file_time_type::clock::now());
        }
        
        return true;
    } catch (const std::filesystem::filesystem_error& e) {
        LOG_ERROR("Failed to touch file: %s", e.what());
        return false;
    } catch (...) {
        LOG_ERROR("Unknown error occurred while touching file");
        return false;
    }
}

bool Bash::gzip(const std::string& file)
{
    try {
        namespace fs = std::filesystem;
        namespace io = boost::iostreams;
        
        fs::path sourcePath(file);
        fs::path targetPath(file + ".gz");
        
        // 检查源文件是否存在
        if (!fs::exists(sourcePath)) {
            LOG_ERROR("Source file does not exist: %s", file.c_str());
            return false;
        }
        
        // 如果源文件是目录，返回false
        if (fs::is_directory(sourcePath)) {
            LOG_ERROR("Cannot gzip a directory: %s", file.c_str());
            return false;
        }
        
        // 使用boost::iostreams进行gzip压缩
        std::ifstream input(sourcePath, std::ios::binary);
        if (!input) {
            LOG_ERROR("Failed to open source file: %s", file.c_str());
            return false;
        }
        
        std::ofstream output(targetPath, std::ios::binary);
        if (!output) {
            LOG_ERROR("Failed to create output file: %s", targetPath.string().c_str());
            return false;
        }
        
        io::filtering_streambuf<io::output> out;
        out.push(io::gzip_compressor(io::gzip_params(9)));  // 最高压缩级别
        out.push(output);
        
        io::copy(input, out);
        
        input.close();
        output.close();
        
        // 删除原始文件
        fs::remove(sourcePath);
        
        return true;
    } catch (const std::exception& e) {
        LOG_ERROR("Failed to gzip file: %s", e.what());
        return false;
    } catch (...) {
        LOG_ERROR("Unknown error occurred while gzipping file");
        return false;
    }
}

bool Bash::zip(const std::string& file, const std::string& name)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path sourcePath(file);
        fs::path zipPath(name + ".zip");
        
        // 检查源文件是否存在
        if (!fs::exists(sourcePath)) {
            LOG_ERROR("Source file does not exist: %s", file.c_str());
            return false;
        }
        
        // 注意：zip格式比较复杂，标准库和boost都不直接支持zip格式
        // 这里使用系统调用（zip命令）来实现
        // 如果需要纯C++实现，可以使用minizip库
        
        // 如果源是目录，需要递归压缩
        if (fs::is_directory(sourcePath)) {
            // 对于目录，使用系统调用（zip命令）
            std::string cmd = "zip -r \"" + zipPath.string() + "\" \"" + sourcePath.string() + "\"";
            std::string result;
            if (!shCmd(cmd, result)) {
                LOG_ERROR("Failed to zip directory: %s", file.c_str());
                return false;
            }
        } else {
            // 对于单个文件，使用系统调用
            std::string cmd = "zip -j \"" + zipPath.string() + "\" \"" + sourcePath.string() + "\"";
            std::string result;
            if (!shCmd(cmd, result)) {
                LOG_ERROR("Failed to zip file: %s", file.c_str());
                return false;
            }
        }
        
        return true;
    } catch (const std::exception& e) {
        LOG_ERROR("Failed to zip file: %s", e.what());
        return false;
    } catch (...) {
        LOG_ERROR("Unknown error occurred while zipping file");
        return false;
    }
}

void Bash::list(const std::string& directory, std::vector<std::string>& files)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path dirPath(directory);
        
        // 检查目录是否存在
        if (!fs::exists(dirPath)) {
            LOG_ERROR("Directory does not exist: %s", directory.c_str());
            return;
        }
        
        if (!fs::is_directory(dirPath)) {
            LOG_ERROR("Path is not a directory: %s", directory.c_str());
            return;
        }
        
        files.clear();
        
        // 遍历目录
        for (const auto& entry : fs::directory_iterator(dirPath)) {
            // 跳过 . 和 ..
            std::string filename = entry.path().filename().string();
            if (filename == "." || filename == "..") {
                continue;
            }
            
            // 获取完整路径
            files.push_back(fs::absolute(entry.path()).string());
        }
        
        // 排序（不区分大小写）
        std::sort(files.begin(), files.end(), [](const std::string& a, const std::string& b) {
            return std::lexicographical_compare(
                a.begin(), a.end(), b.begin(), b.end(),
                [](char c1, char c2) {
                    return std::tolower(c1) < std::tolower(c2);
                });
        });
        
    } catch (const std::filesystem::filesystem_error& e) {
        LOG_ERROR("Failed to list directory: %s", e.what());
    } catch (...) {
        LOG_ERROR("Unknown error occurred while listing directory");
    }
}

// 取出含有绝对路径和文件后缀的文件名
void Bash::getName(const std::string& file, std::string& name)
{
    try {
        namespace fs = std::filesystem;
        
        fs::path filePath(file);
        
        // 获取文件名（不含路径）
        std::string filename = filePath.filename().string();
        
        // 移除所有扩展名（处理.tar.gz等复合扩展名）
        name = filename;
        size_t firstDot = name.find_first_of('.');
        if (firstDot != std::string::npos) {
            name = name.substr(0, firstDot);
        }
        
        // 如果name为空，使用文件名本身
        if (name.empty()) {
            name = filename;
        }
        
    } catch (const std::filesystem::filesystem_error& e) {
        LOG_ERROR("Failed to get file name: %s", e.what());
        name = "";
    } catch (...) {
        LOG_ERROR("Unknown error occurred while getting file name");
        name = "";
    }
}

}  // namespace toolsLib
